package com.yk.dataGatherer.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import com.google.common.collect.Maps;
import com.yk.api.dataGatherer.dto.*;
import com.yk.api.dataGatherer.vo.FieldsVo;
import com.yk.common.core.constant.TdEngIneConstants;
import com.yk.dataGatherer.mapper.TdEngineMapper;
import com.yk.dataGatherer.service.TdEngineService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;


/**
 * TdEngine业务层的实现层
 *
 * @author lmx
 * @date 2023/10/27 15:33
 */
@Service
@Slf4j
@Transactional(isolation = Isolation.DEFAULT, propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
@RequiredArgsConstructor
public class TdEngineServiceImpl implements TdEngineService {

    private final TdEngineMapper tdEngineMapper;

    @Override
    public void createDateBase(String dataBaseName) {
        tdEngineMapper.createDatabase(dataBaseName);
    }

    @Override
    public void createSuperTable(List<FieldsVo> schemaFields, List<FieldsVo> tagsFields, String dataBaseName, String superTableName) {
        tdEngineMapper.createSuperTable(schemaFields, tagsFields, dataBaseName, superTableName);
    }

    @Override
    public void createTable(TableDTO tableDto) {
        tdEngineMapper.createTable(tableDto);
    }

    @Override
    public void delTable(TableDTO tableDto) {
        tdEngineMapper.delTable(tableDto);
    }

    @Override
    public void insertData(TableDTO tableDto) {
        // 主键赋值
        List<Fields> schemaFieldValues = tableDto.getSchemaFieldValues();
        if (CollUtil.isEmpty(schemaFieldValues)) {
            return;
        }
        tdEngineMapper.insertData(tableDto);
    }

    @Override
    public List<Map<String, Object>> selectByTimesTamp(SelectDTO selectDto) {
        return tdEngineMapper.selectByTimestamp(selectDto);
    }

    @Override
    public List<Map<String, Object>> selectByVariableAndTime(SelectDTO selectDto) {
        return tdEngineMapper.selectByVariableAndTime(selectDto);
    }

    @Override
    public List<Map<String, Object>> pageByVariableAndTime(Long pageNum, Long pageSize, SelectDTO selectDto) {
        long start = (pageNum - 1) * pageSize;
        long toIndex = pageNum * pageSize;
        return tdEngineMapper.pageByVariableAndTime(selectDto, toIndex, start);
    }

    @Override
    public void addColumnForSuperTable(String superTableName, FieldsVo fieldsVo) {
        tdEngineMapper.addColumnForSuperTable(superTableName, fieldsVo);
    }

    @Override
    public List<DescribeDTO> getColumn(String dataBaseName, String superTableName) {
        return tdEngineMapper.getColumn(dataBaseName, superTableName);
    }

    @Override
    public void dropColumnForSuperTable(String superTableName, FieldsVo fieldsVo) {
        tdEngineMapper.dropColumnForSuperTable(superTableName, fieldsVo);
    }

    @Override
    public Long getCountByTimesTamp(SelectDTO selectDto) {
        Map<String, Long> countMap = tdEngineMapper.getCountByTimestamp(selectDto);
        if (countMap == null) {
            return 0L;
        }
        return countMap.get("count");
    }

    @Override
    public Map<String, Object> getLastData(SelectDTO selectDto) {
        return tdEngineMapper.getLastData(selectDto);
    }

    @Override
    public void checkTableExists(String dataBaseName, String tableName) {
        tdEngineMapper.checkTableExists(dataBaseName, tableName);
    }

    @Override
    public Map<String, Map<String, Object>> getLastDataByTags(TagsSelectDTO tagsSelectDTO) {
        List<Map<String, Object>> maps = tdEngineMapper.getLastDataByTags(tagsSelectDTO);
        Map<String, Map<String, Object>> objectHashMap = MapUtil.newHashMap();
        for (Map<String, Object> map : maps) {
            objectHashMap.put(map.get(tagsSelectDTO.getTagsName()).toString(), map);
        }
        return objectHashMap;
    }

    @Override
    public List<Map<String, Object>> getDynamicDataByDeviceId(TagsSelectDTO tagsSelectDTO) {
        List<Map<String, Object>> dynamicDataByDeviceId = tdEngineMapper.getDynamicDataByDeviceId(tagsSelectDTO);
        if (CollUtil.isEmpty(dynamicDataByDeviceId)){
            return CollUtil.newArrayList();
        }
        return transformMapToMapList(dynamicDataByDeviceId);
    }

    @Override
    public void delDataByTime(SelectDTO selectDto) {
        tdEngineMapper.delDataByTime(selectDto);
    }

    @Override
    public String selectLatestDataByTime(String parentAddress, String dataBaseName, String tableName, Date startTime, Date endTime) {
        return tdEngineMapper.selectLatestDataByTime(parentAddress, dataBaseName, tableName, startTime, endTime);
    }

    /**
     * 历史数据封装转换
     *
     * @param mapList    历史数据
     * @return 转换后的集合
     */
    private List<Map<String, Object>> transformMapToMapList(List<Map<String, Object>> mapList) {
        List<Map<String, Object>> maps = CollUtil.newArrayList();
        mapList.forEach(it -> {
            Set<String> set = it.keySet();
            Map<String, Object> map = Maps.newHashMap();
            String ts = it.get(TdEngIneConstants.TS).toString();
            String deviceId = it.get(TdEngIneConstants.DEVICE_ID).toString();
            map.put(TdEngIneConstants.TS, ts);
            map.put(TdEngIneConstants.DEVICE_ID, deviceId);
            for (String key : set) {
                if (key.equals(TdEngIneConstants.TS) || key.equals(TdEngIneConstants.DEVICE_ID)) {
                    continue;
                }
                if (Objects.isNull(it.get(key))) {
                    continue;
                }
                // 处理DB5.DBD0类似这种字段出现的转换问题
                String oldKey = key;
                if (it.get(key) instanceof Map) {
                    Map<String, Object> childMap = (Map<String, Object>) it.get(key);
                    Set<String> childSet = childMap.keySet();
                    for (String childKey : childSet) {
                        key = String.format("%s.%s", key, childKey);
                        String childValue = (String) childMap.get(childKey);
                        if (StrUtil.isEmpty(childValue)) {
                            childValue = "NAN";
                        }
                        map.put(key, childValue);
                        // 重置key
                        key = oldKey;
                    }
                }else {
                    map.put(key, it.get(key).toString());
                }
            }
            maps.add(map);
        });
        return maps;
    }
}
